package thema2project;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * This class collects and provides some statistical data on the state of a
 * field. It is flexible: it will create and maintain a counter for any class of
 * object that is found within the field.
 * 
 */

public class FieldStats {
	// Counters for each type of entity (fox, rabbit, etc.) in the simulation.
	@SuppressWarnings("rawtypes")
	private HashMap<Class, Counter> counters;
	// Whether the counters are currently up to date.
	private boolean countsValid;
	private ArrayList<Integer> prevCounts;
	private ArrayList<Integer> nextCounts;
	private String diffCounts;

	/**
	 * Construct a FieldStats object.
	 */
	@SuppressWarnings("rawtypes")
	public FieldStats() {
		// Set up a collection for counters for each type of animal that
		// we might find
		counters = new HashMap<Class, Counter>();
		countsValid = true;
		prevCounts = new ArrayList<Integer>();
		nextCounts = new ArrayList<Integer>();
	}

	/**
	 * Get details of what is in the field.
	 * 
	 * @return A string describing what is in the field.
	 */
	public String getcounts(Field field) {
		StringBuffer buffer = new StringBuffer();
		if (!countsValid) {
			generateCounts(field);
		}
		for (@SuppressWarnings("rawtypes")
		Class key : counters.keySet()) {
			Counter info = counters.get(key);
			buffer.append(" | ");
			buffer.append(info.getCount());
		}
		return buffer.toString();
	}

	/**
	 * Makes a String that contains all names in the current order.
	 * @param field
	 * @return string
	 */
	public String getNames(Field field) {
		StringBuffer buffer = new StringBuffer();
		if (!countsValid) {
			generateCounts(field);
		}
		for (@SuppressWarnings("rawtypes")
		Class key : counters.keySet()) {
			Counter info = counters.get(key);
			buffer.append(" | ");
			if(info.getName().endsWith("Fox") ){
				buffer.append("Foxes");
			}
			if(info.getName().endsWith("Rabbit") ){
				buffer.append("Rabbits");
			}
			if(info.getName().endsWith("Bear") ){
				buffer.append("Bears");
			}
			if(info.getName().endsWith("Hunter") ){
				buffer.append("Hunters");
			}
		}
		return buffer.toString();
	}
	
	/**
	 * Makes a string that contains the actor and the amount of that actor.
	 * @param field
	 * @return String
	 */
	public String getPopulationDetails(Field field) {
		StringBuffer buffer = new StringBuffer();
		if (!countsValid) {
			generateCounts(field);
		}
		for (@SuppressWarnings("rawtypes") Class key : counters.keySet()) {
			Counter info = counters.get(key);
			if(info.getName().endsWith("Fox") ){
				buffer.append("Foxes");
			}
			if(info.getName().endsWith("Rabbit") ){
				buffer.append("Rabbits");
			}
			if(info.getName().endsWith("Bear") ){
				buffer.append("Bears");
			}
			if(info.getName().endsWith("Hunter") ){
				buffer.append("Hunters");
			}
			buffer.append(": ");
			buffer.append(info.getCount());
			buffer.append("    ");
		}
		return buffer.toString();
	}

	
	/**
	 * Creates an string that contains the different between the amount of an actor
	 * @param field
	 * @return string
	 */
	public String getPopulationDiff(Field field) {
		for (@SuppressWarnings("rawtypes")
		Class key : counters.keySet()) {
			Counter countInfo = counters.get(key);
			prevCounts.add(countInfo.getCount());
		}
		if (!countsValid) {
			generateCounts(field);
		}
		for (@SuppressWarnings("rawtypes")
		Class key : counters.keySet()) {
			Counter countInfo = counters.get(key);
			nextCounts.add(countInfo.getCount());
		}
		for (int i = 0; i < nextCounts.size(); i++) {
			int next = nextCounts.get(i);
			int prev = prevCounts.get(i);
			int diff = next - prev;
			if (diff < 0) {
				String s = ("-" + diff + " | ");
				diffCounts = diffCounts + s.toString();
			}
			if (diff > 0) {
				String s = ("+" + diff + " | ");
				diffCounts = diffCounts + s.toString();
			}
		}
		nextCounts.clear();
		prevCounts.clear();
		return diffCounts;
	}

	/**
	 * Invalidate the current set of statistics; reset all counts to zero.
	 */
	public void reset() {
		countsValid = false;
		for (@SuppressWarnings("rawtypes")
		Class key : counters.keySet()) {
			Counter count = counters.get(key);
			count.reset();
		}
	}

	/**
	 * Increment the count for one class of animal.
	 * 
	 * @param animalClass
	 *            The class of animal to increment.
	 */
	public void incrementCount(Class<? extends Object> animalClass) {
		Counter count = counters.get(animalClass);
		if (count == null) {
			// We do not have a counter for this species yet.
			// Create one.
			count = new Counter(animalClass.getName());
			counters.put(animalClass, count);
		}
		count.increment();
	}

	/**
	 * Indicate that an animal count has been completed.
	 */
	public void countFinished() {
		countsValid = true;
	}

	/**
	 * Determine whether the simulation is still viable. I.e., should it
	 * continue to run.
	 * 
	 * @return true If there is more than one species alive.
	 */
	public boolean isViable(Field field) {
		// How many counts are non-zero.
		int nonZero = 0;
		if (!countsValid) {
			generateCounts(field);
		}
		for (@SuppressWarnings("rawtypes")
		Class key : counters.keySet()) {
			Counter info = counters.get(key);
			if (info.getCount() > 0) {
				nonZero++;
			}
		}
		return nonZero > 1;
	}

	/**
	 * Generate counts of the number of foxes and rabbits. These are not kept up
	 * to date as foxes and rabbits are placed in the field, but only when a
	 * request is made for the information.
	 * 
	 * @param field
	 *            The field to generate the stats for.
	 */
	private void generateCounts(Field field) {
		reset();
		for (int row = 0; row < field.getDepth(); row++) {
			for (int col = 0; col < field.getWidth(); col++) {
				Object animal = field.getObjectAt(row, col);
				if (animal != null) {
					incrementCount(animal.getClass());
				}
			}
		}
		countsValid = true;
	}
	/**
	 * calculate the total number of actors.
	 * @param field
	 * @return int
	 */
	public int getTotalPop(Field field) {
		int total = 0;
		if (!countsValid) {
			generateCounts(field);
		}
		for (@SuppressWarnings("rawtypes")
		Class key : counters.keySet()) {
			Counter info = counters.get(key);
			total += info.getCount();
		}
		return total;
	}

	/**
	 * calculate the total number of each actor.
	 * @return int array.
	 */
	public int[] getAllPop() {
		  int[] aantal = new int[(counters.size())];
	        int num = 0;
	        for(@SuppressWarnings("rawtypes") Class key : counters.keySet()) 
	        {
	           Counter info = counters.get(key);
	           aantal[num] = info.getCount();
	           num++;
	        }
	       return aantal;
	}

	/**
	 * creates a string that contain all names of the actors in current order.
	 * @return string
	 */
	public String[] getAllNames() {
		String[] naam = new String[(counters.size())];
        int num = 0;
        for(@SuppressWarnings("rawtypes") Class key : counters.keySet()) 
        {
           Counter info = counters.get(key);
           naam[num] = info.getName();
           num++;
        }
       return naam;
	}

	public ArrayList<Integer> getAllCount() {
		ArrayList<Integer> counts = new ArrayList<Integer>();
		
		for (@SuppressWarnings("rawtypes")
		Class key : counters.keySet()) {
			Counter info = counters.get(key);
			counts.add(info.getCount());
		}
		return counts;
			
	}
}
